﻿using B2BPublisher.BbsSite;
using B2BPublisher.Sv;
using CefSharp;
using CefSharp.Wpf.Experimental;
using Publisher;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Threading;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;

namespace B2BPublisher.UI.Wpf
{
    /// <summary>
    /// WpfDialogBase.xaml 的交互逻辑
    /// </summary>
    public partial class frmMainWpf : Window
    {
        public frmMainWpf()
        {
            CefSharpInit.Init();

            InitializeComponent();
            chrome.RequestContext = new RequestContext();

            _processorManager = new MessageProcessorManager(chrome);

            _processor = new frmMainPageCefMessageProcessor(chrome);
            _publicProcessor = _processorManager.GetPublicMessageProcessor();

            chrome.WpfKeyboardHandler = new WpfImeKeyboardHandler(chrome);
            chrome.JavascriptMessageReceived += Chrome_JavascriptMessageReceived;
            chrome.AddressChanged += Chrome_AddressChanged;
            chrome.FrameLoadEnd += Chrome_FrameLoadEnd;
            chrome.ConsoleMessage += Chrome_ConsoleMessage;
            chrome.LoadError += Chrome_LoadError;
            chrome.IsBrowserInitializedChanged += Chrome_IsBrowserInitializedChanged;
#if DEBUG
            chrome.Address = "http://running.71mulu.com/Projects/PublisherPages/index.html#/mainFrame/frmBbsList?" + GetThemeIdParameter();
            //chrome.Address = "http://static.rongshuweb.com/PublisherPages/index.html#/mainFrame/frmBbsList?" + GetThemeIdParameter();
#else
            chrome.Address = "http://fabu.rongshuweb.com/Projects/PublisherPages/index.html#/mainFrame/frmBbsList?" + GetThemeIdParameter();
#endif

            _baseMessageProcessor = new cefDialogBaseMessageProcessor(chrome);

            _mainServiceManager = new MainServiceManager();
            _mainServiceMessageProcessor = new mainServiceMessageProcessor(chrome, _mainServiceManager);

            this.PreviewMouseLeftButtonDown += WpfDialogBase_PreviewMouseLeftButtonDown;
            this.MouseMove += WpfDialogBase_MouseMove;
            this.PreviewMouseLeftButtonUp += WpfDialogBase_PreviewMouseLeftButtonUp;
            this.SizeChanged += WpfDialogBase_SizeChanged;
            this.WindowStartupLocation = WindowStartupLocation.CenterScreen;
        }

        private string GetThemeIdParameter()
        {
            var id = OemInfo.Instance.AgentId == 1 || OemInfo.Instance.AgentId == 16 || OemInfo.Instance.AgentId == 0 ? 1 : 2;
            return $"themeid={id}";
        }

        private readonly MessageProcessorManager _processorManager;
        private IMessageProcessor _processor;
        private readonly IMessageProcessor _publicProcessor;

        private MainServiceManager _mainServiceManager;
        private mainServiceMessageProcessor _mainServiceMessageProcessor;

        private void WpfDialogBase_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (!ChromeInited)
                return;
            StartInitDragRegion();
        }

        private void StartInitDragRegion()
        {
            Thread thread = new Thread(InitDragRegion);
            thread.Start();
        }

        private void InitDragRegion()
        {
            InitHeaderRegion();
            InitButtonRegions();
        }

        private bool IsMouseInDragRegion(int x, int y)
        {
            if (y < 0 && y >= -4)
                return true;
            if (!IsMouseInRegion(x, y, _headerRegion))
                return false;
            if (_buttonRegions == null || _buttonRegions.Count <= 0)
                return true;
            foreach (var region in _buttonRegions)
            {
                if (IsMouseInRegion(x, y, region))
                    return false;
            }
            return true;
        }

        private bool IsMouseInRegion(int x, int y, Rectangle rect)
        {
            if (x > rect.X + rect.Width || x < rect.X)
                return false;
            if (y > rect.Y + rect.Height || y < rect.Y)
                return false;
            return true;
        }

        private void InitHeaderRegion()
        {
            try
            {
                string widthString = GetJsResult("window.getComputedStyle(document.getElementsByClassName('win-header-outer')[0]).width;");
                if (string.IsNullOrEmpty(widthString))
                    return;
                int width = ToRoundedInt(widthString.Replace("px", ""));

                string heightString = GetJsResult("window.getComputedStyle(document.getElementsByClassName('win-header-outer')[0]).height;");
                if (string.IsNullOrEmpty(heightString))
                    return;
                int height = ToRoundedInt(heightString.Replace("px", ""));
                _headerRegion = new Rectangle(0, 0, width, height);
                //Logger.WriteLog("header region", $"width:{width}, height:{height}");
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex.Message, ex.StackTrace);
            }
        }

        private void InitButtonRegions()
        {
            _buttonRegions = new List<Rectangle>();
            _buttonRegions.Add(GetWindowButtonRegion());
            _buttonRegions.Add(GetToolButtonRegion());
            _buttonRegions.Add(GetLoginButtonRegion());
        }

        private Rectangle GetLoginButtonRegion()
        {
            return GetRegionByClassName("pm-login-box");
        }

        class BoundingClientRectPara
        {
            public double x { get; set; }
            public double y { get; set; }
            public double width { get; set; }
            public double height { get; set; }
        }

        private int ToRoundedInt(string num)
        {
            return (int)Math.Round(To.ToDouble(num));
        }

        private Rectangle GetRegionByClassName(string className)
        {
            try
            {
                var width = GetJsResult($"document.getElementsByClassName('{className}')[0].getBoundingClientRect().width");
                var height = GetJsResult($"document.getElementsByClassName('{className}')[0].getBoundingClientRect().height");
                var x = GetJsResult($"document.getElementsByClassName('{className}')[0].getBoundingClientRect().x");
                var y = GetJsResult($"document.getElementsByClassName('{className}')[0].getBoundingClientRect().y");
                return new Rectangle(ToRoundedInt(x), ToRoundedInt(y), ToRoundedInt(width), ToRoundedInt(height));
            }
            catch(Exception ex)
            {
                Logger.WriteLog(ex.Message, ex.StackTrace);
                return new Rectangle();
            }
        }

        private Rectangle GetWindowButtonRegion()
        {
            return GetRegionByClassName("win-operation-box");
        }

        private Rectangle GetToolButtonRegion()
        {
            return GetRegionByClassName("pm-operation-box");
        }

        private List<Rectangle> _buttonRegions;
        private Rectangle _headerRegion = new Rectangle();

        private string GetJsResult(string function)
        { 
            return _baseMessageProcessor.GetJsResult(function);
        }

        private void RunScript(string function, object para = null)
        {
            _baseMessageProcessor.RunScript(function, para);
        }

        private void WpfDialogBase_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            _isDragging = false;
            this.ReleaseMouseCapture();
        }

        private void WpfDialogBase_MouseMove(object sender, MouseEventArgs e)
        {
            if (_isDragging && e.LeftButton == MouseButtonState.Pressed)
            {
                var currentPoint = e.GetPosition(this);
                double offsetX = currentPoint.X - _startPos.X;
                double offsetY = currentPoint.Y - _startPos.Y;
                this.Left += offsetX;
                this.Top += offsetY;
            }
        }

        private System.Windows.Point _startPos;
        private bool _isDragging = false;

        private void WpfDialogBase_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            var pos = e.GetPosition(chrome);
            if (!IsMouseInDragRegion((int)pos.X, (int)pos.Y))
                return;
            _startPos = e.GetPosition(this);
            _isDragging = true;
            this.CaptureMouse();
        }

        private void Chrome_LoadError(object sender, LoadErrorEventArgs e)
        {
            ShowNetworkErrorDialog();
        }

        private void Chrome_ConsoleMessage(object sender, ConsoleMessageEventArgs e)
        {
            Logger.WriteLog("mainWpf", e.Message);
        }

        private void Chrome_FrameLoadEnd(object sender, FrameLoadEndEventArgs e)
        {
            if (!ChromeInited)
            {
                ChromeInited = true;
                _baseMessageProcessor.ResizeForDpi();

                _mainServiceManager.StartWorkInThread();
            }
            var statusCode = e.HttpStatusCode;
            if (SvHelper.IsMediaPublisher && (statusCode == 404 || statusCode >= 500 && statusCode < 600))
            {
                ShowNetworkErrorDialogInThread();
                return;
            }
            StartInitDragRegion();

            _baseMessageProcessor.LoadEndProcess("");
        }

        private bool ChromeInited = false;

        private void ShowNetworkErrorDialogInThread()
        {
            Thread thread = new Thread(ShowNetworkErrorDialog);
            thread.Start();
        }

        private void ShowNetworkErrorDialog()
        {
            //ERR_NAME_NOT_RESOLVED
            NetworkErrorDialog dialog = new NetworkErrorDialog();
            dialog.ShowDialog();
            if (dialog.Result == "close")
            {
                this.Dispatcher.Invoke(() =>
                {
                    this.Close();
                });
            }
            else
            {
                this.Dispatcher.Invoke(() =>
                {
                    chrome.Reload();
                });
            }
        }

        private void Chrome_AddressChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            var address = e.NewValue.ToString();
            _currentAddress = address;
            _processor = _processorManager.GetMessageProcessor(address);
            if (_processor is IMessageProcessorSetBbs || _processor is frmPublishTaskCefMessageProcessor)
                ReportSoftwareInitFinished();
        }

        private string _currentAddress;

        private void ReportSoftwareInitFinished()
        {
            RunScript("softwareInitFinished");
        }

        private cefDialogBaseMessageProcessor _baseMessageProcessor;

        private void Chrome_JavascriptMessageReceived(object sender, JavascriptMessageReceivedEventArgs e)
        {
            try
            {
                var message = e.Message.ToString();
                if (message == "MP_WindowClose")
                    CloseDialog();
                else if (message == "MP_WindowMaximize")
                    ChangeWindowState(WindowState.Maximized);
                else if (message == "MP_WindowMinimize")
                    ChangeWindowState(WindowState.Minimized);
                else if (message == "MP_WindowNormal")
                    ChangeWindowState(WindowState.Normal);
                else
                {
                    if (_mainServiceMessageProcessor.Process(message))
                        return;
                    if (_publicProcessor.Process(message))
                        return;
                    if (_processor.Process(message))
                        return;
                    Logger.WriteLog("not triggered message", $"message:{message}, currentPage:{_currentAddress}");
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex.Message, ex.StackTrace);
            }
        }

        private void ChangeWindowState(WindowState state)
        {
            this.Dispatcher.Invoke(() =>
            {
                this.WindowState = state;
            });
        }

        private void CloseDialog()
        {
            this.Dispatcher.Invoke(() =>
            {
                this.Close();
            });
        }

        [System.Runtime.InteropServices.DllImport("user32.dll")]
        public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);

        [System.Runtime.InteropServices.DllImport("user32.dll")]
        public static extern bool ReleaseCapture();

        public const int WM_NCLBUTTONDOWN = 0xA1;
        public const int HT_CAPTION = 0x2;

        public void SendHandleMessage()
        {
            var control = new WindowInteropHelper(this);
            if (this.Dispatcher.CheckAccess()) { this.Dispatcher.Invoke(new SendHandleMessageDelegate(SendHandleMessage), new object[] { }); return; }

            var window = GetWindow(this);
            SendMessage(control.Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
        }
        public delegate void SendHandleMessageDelegate();

        private void Chrome_IsBrowserInitializedChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if (!chrome.IsBrowserInitialized)
                return;

            try
            {
                if (chrome.RequestContext != null)
                {
                    Cef.UIThreadTaskFactory.StartNew(delegate
                    {
                        chrome.RequestContext.SetPreference("browser.enable_spellchecking", false, out string error);
                        chrome.RequestContext.SetPreference("spellcheck.dictionaries", new List<object>(), out error);
                    });
                }
            }
            catch(Exception ex)
            {
                Logger.WriteLog(ex.Message, ex.StackTrace);
            }

            /*
            ChromeWidgetMessageInterceptor.SetupLoop(chrome, (message) =>
            {
                if (message.Msg == WM_LBUTTONDOWN)
                {
                    Point point = new Point(message.LParam.ToInt32());
                    if (((DragDropHandler)chrome.DragHandler).draggableRegion.IsVisible(point))
                    {
                        ReleaseCapture();
                        SendHandleMessage();
                    }
                }
            });
            */
        }

    }
}
